/*
 * Daniel Singleton for C++
 * Created by Denes Daniel
 *
 * This file is licensed to you under the Apache License, Version 2.0 :
 * http://www.apache.org/licenses/LICENSE-2.0
 * Distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND.
 */
 
#ifndef STONMANAGER_H
#define STONMANAGER_H

// Singleton Manager implementation
// Responsible for thread-aware construction and destruction of Singleton
// StonManager is the default manager, NOT thread-safe

// Implementation details:
// - stonCreate is used to make sure Singleton is only created once.
//   Once the Singleton is destroyed, it can't be recreated.

// Forward declaration
template <class Ston, template <class> class Manager> class StonKeeper;

template <class Ston>
class StonManager {
// === Declarations needed to be a Manager class for StonKeeper === //
    // The two declarations below define the StonKeeper template instance to be used by (must be the same)
    // - First template parameter must be our template paramteter (Ston)
    // - Second template parameter must be this class template (referring to it through global namespace)
    friend class StonKeeper<Ston, ::StonManager>;
    typedef StonKeeper<Ston, ::StonManager> TKeeper;
    // Method called by StonKeeper to be able to initialize this class
    static void doInit();
    // Function that should quickly return a pointer to the singleton instance (if it's alive) or a null pointer (if it's not)
    static Ston * getSingleton();
    // Function that should return a pointer to the singleton instance (safely creating it if necessary, but only once)
    static Ston * makeSingleton();
    // Function that should kill the singleton instance (and prevent creation of it later on)
    static void killSingleton();
    // Private constructor (anything in this class must only be accessible to the friend StonKeeper)
    StonManager();

// === Actual implementation details of Manager class === //
    // Everything must be private (anything in this class must only be accessible to the friend StonKeeper)
    static bool stonCreate;
    static Ston * stonInst;
};

template <class Ston>
bool StonManager<Ston>::stonCreate = true;

template <class Ston>
Ston * StonManager<Ston>::stonInst = 0;

// Method called by StonKeeper (for the Manager to be able to initialize itself)
template <class Ston>
void StonManager<Ston>::doInit() {
}

// Function that should quickly return a pointer to the singleton instance (if it's alive) or a null pointer (if it's not)
template <class Ston>
inline Ston * StonManager<Ston>::getSingleton() {
    return stonInst;
}

// Function that should return a pointer to the singleton instance (safely creating it if necessary, but only once)
template <class Ston>
Ston * StonManager<Ston>::makeSingleton() {
    if(stonCreate) {
        stonInst = TKeeper::newSingleton();
        stonCreate = false;
    }
    return getSingleton();
}

// Function that should kill the singleton instance (and prevent creation of it later on)
template <class Ston>
void StonManager<Ston>::killSingleton() {
    stonCreate = false;
    if(stonInst) {
        TKeeper::delSingleton(stonInst);
        stonInst = 0;
    }
}

#endif
